/*
 * Copyright 2010 Assert Developments
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * 	http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package be.ad.coffeebreak.rest;

import be.ad.coffeebreak.domain.*;
import be.ad.coffeebreak.services.ProjectHoursService;
import be.ad.coffeebreak.services.ProjectsService;
import be.ad.coffeebreak.services.UsersService;

import javax.annotation.ManagedBean;
import javax.ejb.EJB;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import java.io.Serializable;
import java.net.URI;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;

/**
 * Rest service for internal usage only.
 * <p/>
 * Provides the following uris:
 * - /
 * - /users
 * - /users/{userId}
 * - /users/{userId}/projects
 * - /users/{userId}/projects/{projectId}
 * - /users/{userId}/projects/{projectId}/hours/{date}
 * <p/>
 * <p/>
 * GET /internal/users/{userId}
 * <p/>
 * DESCRIPTION
 * Return the specified user resource.
 * <p/>
 * REQUEST PARAMETERS
 * - userId   unsigned long   id of the user to return.
 * <p/>
 * QUERY PARAMETERS
 * - none
 * <p/>
 * AUTHORIZATION
 * - everyone
 * <p/>
 * REQUEST BODY
 * - none
 * <p/>
 * RESPONSE
 * - user resource
 * <p/>
 * <p/>
 * <p/>
 * User Resource Representation
 * <p/>
 * application/json
 * - id       unsigned long   the unique identifier for the user
 * - name     string          the name of the user
 *
 * @author Stefan Bangels
 */
@ManagedBean
@Path("/internal")
public class InternalRestService implements Serializable {

    @Context
    protected UriInfo uriInfo;

    @EJB
    protected UsersService usersService;

    @EJB
    protected ProjectsService projectsService;

    @EJB
    ProjectHoursService projectHoursService;

    @GET
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public Object getRoot() {
        return new Object() {
            @SuppressWarnings("unused")
            public String getUsersUri() {
                return "/users";
            }
        };
    }

    @GET
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    @Path("/users")
    public List<User> findUsers(@QueryParam("email") String email) {
        if (email == null) {
            return usersService.findAllUsers();
        } else {
            return Arrays.asList(usersService.findUserByEmail(email));
        }
    }

    @POST
    @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    @Path("/users")
    public Response createUser(User user) {
        user.setId(null);
        user = usersService.saveUser(user);
        URI uri = uriInfo.getAbsolutePathBuilder().path(user.getId().toString()).build();
        return Response.created(uri).build();
    }

    @GET
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    @Path("/users/{userId}")
    public Response findUserById(@PathParam("userId") long userId) {
        User user = usersService.findUserById(userId);
        if (user == null) {
            return Response.status(Response.Status.NOT_FOUND).build();
        }
        return Response.ok(user).build();
    }

    @PUT
    @Path("/users/{userId}")
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public User updateUser(User user, @PathParam("userId") long userId) {
        user.setId(userId);
        return usersService.saveUser(user);
    }

    @DELETE
    @Path("/users/{userId}")
    public Response deleteUser(@PathParam("userId") Long userId) {
        usersService.deleteUser(userId);
        return Response.noContent().build();
    }

    @GET
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    @Path("/users/{userId}/projects")
    public List<Project> findAllUserProjects(@PathParam("userId") long userId) {
        return projectsService.findProjectsByUserId(userId);
    }

    @POST
    @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    @Path("/users/{userId}/projects")
    public Response createProduct(Project project, @PathParam("userId") long userId) {
        project.setId(null);
        project.setUserId(userId);
        project = projectsService.saveProject(project);
        URI uri = uriInfo.getAbsolutePathBuilder().path(project.getId().toString()).build();
        return Response.created(uri).build();
    }

    @GET
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    @Path("/users/{userId}/projects/{projectId}")
    public Response findProjectById(@PathParam("projectId") long projectId) {
        Project project = projectsService.findProjectById(projectId);
        if (project == null) {
            return Response.status(Response.Status.NOT_FOUND).build();
        }
        return Response.ok(project).build();
    }

    @PUT
    @Path("/users/{userId}/projects/{projectId}")
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public Project updateUser(Project project, @PathParam("projectId") long projectId) {
        project.setId(projectId);
        return projectsService.saveProject(project);
    }

    @DELETE
    @Path("/users/{userId}/projects/{projectId}")
    public Response deleteProject(@PathParam("projectId") Long projectId) {
        projectsService.deleteProject(projectId);
        return Response.noContent().build();
    }

    @GET
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    @Path("/users/{userId}/projects/{projectId}/hours/{date}")
    public Response findProjectHoursByProjectIdAndDate(
            @PathParam("projectId") long projectId, @PathParam("date") String dateString) {
        Date date;
        try {
            date = new SimpleDateFormat("yyyyMMdd").parse(dateString);
        } catch (ParseException e) {
            return Response.status(Response.Status.BAD_REQUEST).build();
        }
        ProjectHours projectHours = projectHoursService.findProjectHours(projectId, date);
        if (projectHours == null) {
            projectHours = new ProjectHours();
            projectHours.setProjectId(projectId);
            projectHours.setDate(date);
            projectHours.setActualProjectHours(new HashSet<ActualProjectHours>());
            projectHours.setExpectedProjectHours(new HashSet<ExpectedProjectHours>());
            projectHours.setComments("");
        }
        return Response.ok(projectHours).build();
    }

    @PUT
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    @Path("/users/{userId}/projects/{projectId}/hours/{date}")
    public Response updateProjectHours(
            ProjectHours projectHours, @PathParam("projectId") long projectId, @PathParam("date") String dateString) {
        Date date;
        try {
            date = new SimpleDateFormat("yyyyMMdd").parse(dateString);
        } catch (ParseException e) {
            return Response.status(Response.Status.BAD_REQUEST).build();
        }
        projectHours.setProjectId(projectId);
        projectHours.setDate(date);
        projectHoursService.saveProjectHours(projectHours);
        return Response.ok(projectHours).build();
    }

    @DELETE
    @Path("/users/{userId}/projects/{projectId}/hours/{date}")
    public Response deleteProjectHours(@PathParam("projectId") long projectId, @PathParam("date") String dateString) {
        Date date;
        try {
            date = new SimpleDateFormat("yyyyMMdd").parse(dateString);
        } catch (ParseException e) {
            return Response.status(Response.Status.BAD_REQUEST).build();
        }
        projectHoursService.deleteProjectHours(projectId, date);
        return Response.noContent().build();
    }

}
